//Header files
#include <stdio.h>
#include <string.h>
#include <spu_mfcio.h>
#include "common.h"

//Declaring matrices
unsigned int matrixA[NUM+1][MATRIX_SIZE]  QWORD_ALIGNED;
unsigned int matrixB[MATRIX_SIZE][NUM+1]  QWORD_ALIGNED;
unsigned int matrixC[NUM+1][NUM+1]  QWORD_ALIGNED;

//==============================================================================
CONTROL_BLOCK cb QWORD_ALIGNED;
//==============================================================================

int main(uint64_t speid,uint64_t argp, uint64_t envp){
  int i,j,k;
  int totalwordsA,totalwordsB,totalwordsC;
  int tid = (int) envp;
  
  //============================================================================
  // This part is used to Data input using DMA to get it from PPE
  // DMA in control block and wait for completion
  mfc_get(&cb,argp,sizeof(cb),0,0, 0);
  mfc_write_tag_mask(1 << 0);
  mfc_read_tag_status_all();

  // DMA in matrixB and wait for completion, Be careful of 16 KB
  int* spuptr = &matrixB[0][0];  // dst, start addr 
  int* ppuptr = cb.b;           // src, start addr
  totalwordsB = sizeof(matrixB) >> 2;

  const int dt_unit = 4096;    // in words, or 4 bytes
  
  int* spulast = spuptr + totalwordsB;
  while ( spuptr < spulast ) {
    int nwords = ( spuptr + dt_unit > spulast ) ? (spulast - spuptr) : dt_unit;
    
    mfc_get(spuptr, ppuptr, 4*nwords, 0,0,0);
    mfc_write_tag_mask(1 << 0);
    mfc_read_tag_status_all();
    spuptr += dt_unit;
    ppuptr += dt_unit;
  }   
    
  // DMA in matrixA and wait for completion, Be careful of 16 KB
	spuptr = &matrixA[0][0];  // dst, start addr 
	ppuptr = cb.a;           // src, start addr
	totalwordsA = sizeof(matrixA) >> 2;

	spulast = spuptr + totalwordsA;
    
  while ( spuptr < spulast ) {
    int nwords = ( spuptr + dt_unit > spulast ) ? (spulast - spuptr) : dt_unit;
    mfc_get(spuptr, ppuptr, 4*nwords, 0,0,0);
    mfc_write_tag_mask(1 << 0);
    mfc_read_tag_status_all();
    spuptr += dt_unit;
    ppuptr += dt_unit;
  }    

  //============================================================================
  
//printf("entering computation %d\n",tid);

  /* Do computing of matrix multiplication */
  for(i=0;i<NUM;i++)
  {            
	for(j=0;j<NUM;j++)            
	{                
		matrixC[i][j]=0;                
		for(k=0;k<MATRIX_SIZE;k++)                
		{                    
			matrixC[i][j]+=matrixA[i][k]*matrixB[k][j];
		} 
		//printf("%d ", matrixC[i][j]);               
	}  
	//printf("\n");          
  }

//send data back to ppu

	spuptr = &matrixC[0][0];  
	ppuptr = cb.c; 
	totalwordsC = sizeof(matrixC) >> 2;

  	spulast = spuptr + totalwordsC; 

    while ( spuptr < spulast ) {
    int nwords = ( spuptr + dt_unit > spulast ) ? (spulast - spuptr) : dt_unit;
    
    mfc_put(spuptr, ppuptr, 4*nwords, 0,0,0);
    mfc_write_tag_mask(1 << 0);
    mfc_read_tag_status_all();
    spuptr += dt_unit;
    ppuptr += dt_unit;
  }  


  return 0;  
}
